using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms.Design;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Collections;

using System.Windows.Forms;
using System.Drawing;
using Camalon.Drawing;

namespace Camalon.Drawing.Design
{
	/// <summary>
	/// Summary description for VectorShapeDesigner.
	/// </summary>
	public class VectorShapeDesigner:ShapeDesigner
	{

	
		DesignerVerb	_verbAddPoint;
		DesignerVerb	_verbRemovePoint;
		DesignerVerb    _verbInsertPoint;
		DesignerVerb	_verbEditPoints;
		DesignerVerb	_verbAnchorPoint;
		
		protected DesignerVerb VerbAnchorPoint
		{
			get{ return _verbAnchorPoint;}
		}

		protected DesignerVerb VerbAddPoint
		{
			get{ return _verbAddPoint;}
		}

		protected DesignerVerb VerbRemovePoint
		{
			get{ return _verbRemovePoint;}
		}

		protected DesignerVerb VerbInsertPoint
		{
			get{ return _verbInsertPoint;}
		}

		protected virtual string TextVerbAnchorPoint
		{
			get{ return "Anchor Point";}
		}

		protected virtual string TextVerbAdd
		{
			get{ return "Add Point";}
		}

		protected virtual string TextVerbInsert
		{
			get{ return "Insert Point";}
		}

		protected virtual string TextVerbRemove
		{
			get{ return "Remove Point";}
		}


		[Browsable(false)]
		public virtual bool CanAddPoints
		{
			get{ return true;}
		}

		[Browsable(false)]
		public virtual bool CanRemovePoints
		{
			get{ return true;}
		}

		[Browsable(false)]
		public virtual bool CanInsertPoints
		{
			get{ return true;}
		}

		[Browsable(false)]
		public virtual bool CanEditPoints
		{
			get{ return true;}
		}


		public override System.ComponentModel.Design.DesignerVerbCollection Verbs
		{
			get
			{
				DesignerVerbCollection verbs = base.Verbs;

				VectorShape shape = this.Component as VectorShape;

				if( shape != null && verbs != null && this.CanEditPoints)
				{

					if(  _verbAnchorPoint == null)	
					{
						_verbAnchorPoint	= new DesignerVerb(TextVerbAnchorPoint, new EventHandler(On_AnchorPoint));
						
						verbs.Insert(0, _verbAnchorPoint );
					}

					if( this.CanInsertPoints && _verbInsertPoint == null)	
					{
						_verbInsertPoint	= new DesignerVerb(TextVerbInsert, new EventHandler(On_InsertPoint));
						
						verbs.Insert(0, _verbInsertPoint );
					}
					if( this.CanRemovePoints && _verbRemovePoint == null)	
					{
						_verbRemovePoint	= new DesignerVerb(TextVerbRemove, new EventHandler(On_RemovePoint));	
						verbs.Insert(0, _verbRemovePoint );
					}
					if( this.CanAddPoints && _verbAddPoint == null)		
					{
						_verbAddPoint		= new DesignerVerb(TextVerbAdd, new EventHandler(On_AddPoint));
						verbs.Insert(0, _verbAddPoint );
					}
					if( this.CanEditPoints && _verbEditPoints == null)	
					{
						_verbEditPoints		= new DesignerVerb("Edit Mode", new EventHandler(On_EditMode));
						_verbEditPoints.Checked = false;
						Adornment.PointsEditingMode = false;

						verbs.Insert(0, _verbEditPoints );
					}
				}

				return verbs;
			}
		}



		PropertyDescriptor	_propPoints		= TypeDescriptor.GetProperties(typeof( VectorShape ))["Points"];

		private void On_AnchorPoint(object sender, EventArgs e)
		{
			VectorShape shape = this.Component as VectorShape;
			if( shape == null) return;
			

			ShapeAdornment a = base.Adornment;

			using ( DesignerTransaction tx = this.DesignerHost.CreateTransaction("Anchor point"))
			{
				if(this.OnAnchorPoint( shape, _propPoints, a.EditingPointIndices )) tx.Commit();
				else tx.Cancel();
			}
		}

		protected virtual bool OnAnchorPoint( VectorShape shape, PropertyDescriptor propPoints, int pointIndex)
		{

			AnchorPoint[] points = shape.Points;
			AnchorPoint oldValue = points[ pointIndex ];
			using(PropertyGridForm propForm = new PropertyGridForm(oldValue))
			{
				if( propForm.ShowDialog() == DialogResult.Cancel) return false;

				AnchorPoint newValue = propForm.GetAnchorValue();

				if( oldValue == newValue) return false;

				points[ pointIndex ]  = newValue;

				propPoints.SetValue(shape, points);
				return true;
			}

		}


		private void On_AddPoint(object sender, EventArgs e)
		{
			VectorShape shape = this.Component as VectorShape;
			if( shape == null) return;

			ShapeAdornment a = base.Adornment;
			Point lastHitPoint = a.LastHitTest;

			int rem = int.MaxValue; 
			Math.DivRem( shape.Rotation, 360, out rem ); 
			if( rem != 0 )
				using(Matrix m = new Matrix())
				{
					PointF anchor = shape.GetRotatingPoint();
					m.RotateAt(-shape.Rotation, anchor, MatrixOrder.Append);

					Point[] transCurrent = new Point[]{ lastHitPoint};
					m.TransformPoints( transCurrent );
					lastHitPoint = transCurrent[0];
				}


			using ( DesignerTransaction tx = this.DesignerHost.CreateTransaction("Add point"))
			{
				this.OnAddPoint( shape, _propPoints, lastHitPoint);
				tx.Commit();
			}
		}

		protected virtual void OnAddPoint( VectorShape shape, PropertyDescriptor propPoints, AnchorPoint point )
		{
			AnchorPoint[] points = shape.Points;
			ArrayList list = new ArrayList( points );
			list.Add( point );

			points = new AnchorPoint[list.Count];
			list.CopyTo( points);


			propPoints.SetValue(shape, points);
		}


		private void On_RemovePoint(object sender, EventArgs e)
		{
			VectorShape shape = this.Component as VectorShape;
			if( shape == null) return;
			

			ShapeAdornment a = base.Adornment;

			using ( DesignerTransaction tx = this.DesignerHost.CreateTransaction("Remove point"))
			{
				this.OnRemovePoint( shape, _propPoints, a.EditingPointIndices );
				tx.Commit();
			}
		}

		protected virtual void OnRemovePoint( VectorShape shape, PropertyDescriptor propPoints, int removeAt )
		{

			AnchorPoint[] points = shape.Points;
			ArrayList list = new ArrayList( points );
			list.RemoveAt( removeAt );
			points = new AnchorPoint[list.Count];
			list.CopyTo( points);

			propPoints.SetValue(shape, points);

		}


		private void On_InsertPoint(object sender, EventArgs e)
		{
			VectorShape shape = this.Component as VectorShape;
			if( shape == null) return;

			ShapeAdornment a = base.Adornment;
			Point lastHitPoint = a.LastHitTest;
			int rem = int.MaxValue; 
			Math.DivRem( shape.Rotation, 360, out rem ); 
			if( rem != 0 )
				using(Matrix m = new Matrix())
				{
					PointF anchor = shape.GetRotatingPoint();
					m.RotateAt(-shape.Rotation, anchor, MatrixOrder.Append);

					Point[] transCurrent = new Point[]{ lastHitPoint };
					m.TransformPoints( transCurrent );
					lastHitPoint = transCurrent[0];
				}

			using ( DesignerTransaction tx = this.DesignerHost.CreateTransaction("Insert point"))
			{
				this.OnInsertPoint( shape, _propPoints, lastHitPoint, a.EditingPointIndices);
				tx.Commit();
			}
		}

		protected virtual void OnInsertPoint( VectorShape shape, PropertyDescriptor propPoints,AnchorPoint point, int insertAt )
		{
			AnchorPoint[] points = shape.Points;
			ArrayList list = new ArrayList( points );
			list.Insert( insertAt,point );
			points = new AnchorPoint[list.Count];
			list.CopyTo( points);

			_propPoints.SetValue(shape, points);

		}


		private void On_EditMode(object sender, EventArgs e)
		{
			_verbEditPoints.Checked = !_verbEditPoints.Checked;
			Adornment.PointsEditingMode = _verbEditPoints.Checked;
		}
	}
}
